package com.gnerv.battle.boot.security.config;

import com.gnerv.battle.boot.security.autoconfigure.BattleSecurityConfigProperties;
import com.gnerv.battle.boot.security.config.filter.BattleCustomVerificationCodeFilter;
import com.gnerv.battle.boot.security.provider.BattleDaoAuthenticationProvider;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * @author Gnerv LiGen
 */
@Configuration
@EnableWebSecurity
public class BattleSecurityConfig {

    @Resource
    private BattleSecurityConfigProperties battleSecurityConfigProperties;

    @Resource
    private AccessDeniedHandler accessDeniedHandler;

    @Resource
    private BattleCustomAuthorizationManager battleCustomAuthorizationManager;

    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    private AuthenticationSuccessHandler authenticationSuccessHandler;

    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;

    @Resource
    private LogoutSuccessHandler logoutSuccessHandler;

    @Resource
    private BattleCustomVerificationCodeFilter customVerificationCodeFilter;

    @Bean
    @Order(Ordered.LOWEST_PRECEDENCE - 12)
    public SecurityFilterChain securitySessionFilterChain(HttpSecurity http) throws Exception {
        http
                // 关闭 cors
                .cors(AbstractHttpConfigurer::disable)
                // 关闭 csrf
                .csrf(AbstractHttpConfigurer::disable)
                // 关闭匿名访问
                .anonymous(AbstractHttpConfigurer::disable)
                // 加入验证码校验
                .addFilterBefore(customVerificationCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeHttpRequests(authorize -> authorize
                        // 所有请求 使用自定义认证管理器进行权限校验
                        .anyRequest().access(battleCustomAuthorizationManager)
                )
                .exceptionHandling(exceptionHandlingCustomizer -> exceptionHandlingCustomizer
                        // 自定义认证失败处理
                        .authenticationEntryPoint(authenticationEntryPoint)
                        // 自定义授权失败处理
                        .accessDeniedHandler(accessDeniedHandler))
                .httpBasic(withDefaults())
                .formLogin(formLogin -> formLogin
                        // 自定义登录页面
                        .loginPage(battleSecurityConfigProperties.getLoginPageUrl()).permitAll()
                        // 自定义登录地址
                        .loginProcessingUrl(battleSecurityConfigProperties.getLoginUrl()).permitAll()
                        // 自定义登录成功处理
                        .successHandler(authenticationSuccessHandler)
                        // 自定义登录失败处理
                        .failureHandler(authenticationFailureHandler)
                ).logout(logout -> logout
                        // 自定义注销地址
                        .logoutUrl(battleSecurityConfigProperties.getLogoutUrl()).permitAll()
                        // 自定义注销成功处理
                        .logoutSuccessHandler(logoutSuccessHandler)
                )
                .sessionManagement(session -> session
                        // 自定义同一账户同时登录数量
                        .maximumSessions(battleSecurityConfigProperties.getMaximumSessions())
                );
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public BattleDaoAuthenticationProvider daoAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        BattleDaoAuthenticationProvider provider = new BattleDaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        provider.setBattleSecurityConfigProperties(battleSecurityConfigProperties);
        return provider;
    }

}
